import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import org.jbox2d.collision.CircleDef;
import org.jbox2d.collision.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;

import pulpcore.animation.Easing;
import pulpcore.animation.Fixed;
import pulpcore.image.BlendMode;
import pulpcore.image.Colors;
import pulpcore.image.CoreGraphics;
import pulpcore.image.CoreImage;
import pulpcore.sprite.Sprite;
import pulpfizz.physics.Actor;
import pulpfizz.physics.CollisionUtils;
import pulpfizz.physics.Material;
import pulpfizz.physics.PolygonUtils;
import pulpfizz.pulp.body.ImageBodySprite;
import pulpfizz.pulp.body.Java2DBodySprite;
import pulpfizz.pulp.body.PhysicsLayer;
import pulpfizz.pulp.body.ShapeBodyDrawer;

public class Arena extends Actor
{
	public static float SIZE;
	public static float THICKNESS;

	private PhysicsLayer physics;

	ArrayList<Body> bodies;
	Body player1Sensor;
	Shape player1Shield;
	Body player2Sensor;
	Shape player2Shield;

	private ArrayList<Body> pieces;
	private ArrayList<Fixed> poseTweens;

	static float PI = (float) Math.PI;

	static float GAP_SIZE = PI / 10f;
	float[] pose1 = new float[] { -GAP_SIZE, 0, 0, GAP_SIZE, -GAP_SIZE, 0, 0, GAP_SIZE, 0, PI };
	float[] pose2 = new float[] { -GAP_SIZE, 0, 0, GAP_SIZE, -GAP_SIZE, 0, 0, GAP_SIZE, 0, PI };
	float[] curPose;
	private boolean twoPlayers;

	public Arena(PhysicsLayer physics, float SIZE, float THICKNESS, boolean twoPlayers)
	{
		this.twoPlayers = twoPlayers;
		physics.add(new Sprite(0, 0, 0, 0)
		{

			@Override
			protected void drawSprite(CoreGraphics g)
			{
			}

			@Override
			public void update(int elapsedTime)
			{
				updateArena(elapsedTime);
			}
		});

		this.SIZE = SIZE;
		this.THICKNESS = THICKNESS;
		this.physics = physics;

		createBodies();
	}

	public void createBodies()
	{
		// Create a circle bounding box.
		float w = physics.getPhysicsWidth();
		float h = physics.getPhysicsHeight();

		pieces = new ArrayList<Body>();
		poseTweens = new ArrayList<Fixed>();
		for (int i = 0; i < 8; i++)
		{
			Body b = createArcBody(physics, SIZE, THICKNESS, i * 45, (i + 1) * 45, true);
			CollisionUtils.maskOut(Player.CATEGORY, b);
			//			physics.add(new Java2DBodySprite(b, physics, 1));
			pieces.add(b);
		}

		CircleDef cd = new CircleDef();
		cd.radius = SIZE / 3.3f;
		cd.localPosition = new Vec2(SIZE, 0);

		player1Sensor = createArcBody(physics, SIZE, THICKNESS / 10, -15, 15, false);
		player1Shield = player1Sensor.createShape(cd);
		player2Sensor = createArcBody(physics, SIZE, THICKNESS / 10, -15, 15, false);
		player2Shield = player2Sensor.createShape(cd);
		CollisionUtils.setSensor(true, player1Sensor, player2Sensor);
		pieces.add(player1Sensor);
		pieces.add(player2Sensor);
		createSpriteForSensor(player1Sensor, Colors.BLUE);
		if (twoPlayers)
		{
			createSpriteForSensor(player2Sensor, Colors.RED);
			addBody(player2Sensor);
		}

		for (Body b : pieces)
		{
			Fixed f = new Fixed(PI / 2);
			poseTweens.add(f);
		}

		// Handle our contact listening stuff.
		addToGroup(TwoPlayerScene.ARENA_SENSOR);
		addBody(player1Sensor);
	}

	ImageBodySprite createSpriteForSensor(Body b, int color)
	{
		ImageBodySprite spr = new ImageBodySprite(b, physics);
		CoreImage img = CoreImage.load("goal.png");
		img = img.tint(color);
		spr.setImage(img);
		spr.setBlendMode(BlendMode.Add());
		spr.height.set(spr.height.get() * 2);
		spr.width.set(spr.width.get() * 2);
		physics.add(spr);
		return spr;
	}

	public void pose(float[] pose, int duration)
	{
		for (int i = 0; i < poseTweens.size(); i++)
		{
			Fixed f = poseTweens.get(i);
			f.animateTo(pose[i], duration, Easing.REGULAR_IN_OUT);
		}
	}

	public void updateArena(int elapsedTime)
	{
		for (int i = 0; i < poseTweens.size(); i++)
		{
			Body b = pieces.get(i);
			Fixed f = poseTweens.get(i);
			f.update(elapsedTime);
			if (f.get() != 0)
				b.setXForm(b.getPosition(), (float) f.get());
		}
	}

	public static Body createArcBody(PhysicsLayer physics, float radius, float thickness, float angleLo, float angleHi,
			boolean createSprite)
	{
		// Create a hollow circle.
		Ellipse2D.Float ellipse = new Ellipse2D.Float();
		Rectangle2D.Float rect = new Rectangle2D.Float();
		Ellipse2D.Float inner = new Ellipse2D.Float();
		ellipse.setFrameFromCenter(0, 0, radius, radius);
		inner.setFrameFromCenter(0, 0, radius - thickness, radius - thickness);
		Area a = new Area(ellipse);
		a.subtract(new Area(inner));

		// Create a wedge-shaped arc.
		Arc2D.Float arc = new Arc2D.Float();
		arc.setArcByCenter(0, 0, radius, angleLo, angleHi - angleLo, Arc2D.PIE);

		a.intersect(new Area(arc));
		Body b = PolygonUtils.areaToBody(physics, a, radius / 100);

		// Add nice circles at the end to round it out.
		float rMid = radius - thickness / 2f;
		float startX = (float) Math.cos(Math.toRadians(angleLo)) * rMid;
		float startY = -(float) Math.sin(Math.toRadians(angleLo)) * rMid;
		float endX = (float) Math.cos(Math.toRadians(angleHi)) * rMid;
		float endY = -(float) Math.sin(Math.toRadians(angleHi)) * rMid;
		CircleDef cd = new CircleDef();
		cd.radius = thickness / 2f;
		cd.localPosition = new Vec2(startX, startY);
		b.createShape(cd);
		cd.localPosition = new Vec2(endX, endY);
		b.createShape(cd);

		Material m = Material.WOOD();
		m.setRestitution(0.0f);

		if (createSprite)
		{
			Ellipse2D.Float startC = new Ellipse2D.Float();
			startC.setFrameFromCenter(startX, startY, startX - thickness / 2, startY + thickness / 2);
			Ellipse2D.Float endC = new Ellipse2D.Float();
			endC.setFrameFromCenter(endX, endY, endX - thickness / 2, endY + thickness / 2);

			a.add(new Area(startC));
			a.add(new Area(endC));

			Area trueArea = a;
			ShapeBodyDrawer drawer = new ShapeBodyDrawer(trueArea)
			{
				@Override
				public void drawBody(PhysicsLayer physics, Body b, Graphics2D g2)
				{
					g2.setStroke(new BasicStroke(1f / physics.getScaling() * 2f));
					g2.setPaint(Color.WHITE);
					//					g2.draw(shape);
					g2.fill(shape);
				}
			};
			Java2DBodySprite j2b = new Java2DBodySprite(b, physics, 2);
			j2b.setPadding(2);
			j2b.loadImages();
			j2b.setBodyDrawer(drawer);
//			j2b.setBlendMode(BlendMode.Add());
			j2b.alpha.set(255);
			physics.add(j2b);
		}

		return b;
	}
}
